import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'dart:typed_data';

enum ConnectStatus { connecting, succeed, notConnected }

abstract class SocketListener {
  void dataHandle(String data);
}

class ClientSocket {
  Socket? _socket;
  final List<SocketListener> _listeners = [];
  final List<dynamic> _messages = [];
  late final dynamic _host;
  late final int _port;
  bool _needReconnect = true;
  ConnectStatus _status = ConnectStatus.notConnected;
  late Timer? _timer;
  ClientSocket(host, port) {
    _host = host;
    _port = port;
    _connect();
  }
  _connect() async {
    try {
      _needReconnect = true;
      _status = ConnectStatus.connecting;
      _socket = await Socket.connect(_host, _port);
      _flushMsg();
      _status = ConnectStatus.succeed;
      _socket!.listen(_dataHandler, onDone: _doneHandler, cancelOnError: false);
    } catch (e) {
      log("Obu连接失败");
      _status = ConnectStatus.notConnected;
    }
  }

  _dataHandler(Uint8List data) {
    var msg = String.fromCharCodes(data);
    for (var listener in _listeners) {
      listener.dataHandle(msg);
    }
  }

  _doneHandler() {
    _socket = null;
    if (_needReconnect) {
      _timer = Timer.periodic(const Duration(seconds: 5), (timer) {
        _reconnect();
      });
    }
  }

  _reconnect() {
    if (_status == ConnectStatus.notConnected) {
      //还没有连接成功，那就需要继续连接
      _connect();
    } else if (_status == ConnectStatus.connecting) {
      //正在连接中，那就啥也别干，等着吧
      return false;
    } else {
      //如果连接成功了，那就取消轮询
      _timer?.cancel();
    }
  }

  subscribe(SocketListener listener) {
    _listeners.add(listener);
  }

  unsubscribe(SocketListener listener) {
    _listeners.remove(listener);
  }

  send(dynamic msg) {
    if (_socket == null) {
      _messages.add(msg);
    } else {
      _socket!.write(msg);
    }
  }

  _flushMsg() {
    for (var msg in _messages) {
      _socket!.write(msg);
    }
  }

  close() {
    //手动关闭的连接 不需要重连
    _needReconnect = false;
    _timer?.cancel();
    _socket?.close();
  }
}
